home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Freeware / Miro 1.0 / Miro_Installer.exe / xulrunner / chrome / toolkit.jar / content / global / filepicker.js < prev    next >
Encoding:
Text File  |  2005-03-02  |  23.9 KB  |  829 lines

  1. //@line 44 "/c/mozilla/toolkit/components/filepicker/content/filepicker.js"
  2.  
  3. const nsIFilePicker       = Components.interfaces.nsIFilePicker;
  4. const nsIDirectoryServiceProvider = Components.interfaces.nsIDirectoryServiceProvider;
  5. const nsIDirectoryServiceProvider_CONTRACTID = "@mozilla.org/file/directory_service;1";
  6. const nsITreeBoxObject = Components.interfaces.nsITreeBoxObject;
  7. const nsIFileView = Components.interfaces.nsIFileView;
  8. const nsFileView_CONTRACTID = "@mozilla.org/filepicker/fileview;1";
  9. const nsITreeView = Components.interfaces.nsITreeView;
  10. const nsILocalFile = Components.interfaces.nsILocalFile;
  11. const nsIFile = Components.interfaces.nsIFile;
  12. const nsLocalFile_CONTRACTID = "@mozilla.org/file/local;1";
  13. const nsIPromptService_CONTRACTID = "@mozilla.org/embedcomp/prompt-service;1";
  14.  
  15. var sfile = Components.classes[nsLocalFile_CONTRACTID].createInstance(nsILocalFile);
  16. var retvals;
  17. var filePickerMode;
  18. var homeDir;
  19. var treeView;
  20.  
  21. var textInput;
  22. var okButton;
  23.  
  24. var gFilePickerBundle;
  25.  
  26. // name of new directory entered by the user to be remembered
  27. // for next call of newDir() in case something goes wrong with creation
  28. var gNewDirName = { value: "" };
  29.  
  30. function filepickerLoad() {
  31.   gFilePickerBundle = document.getElementById("bundle_filepicker");
  32.  
  33.   textInput = document.getElementById("textInput");
  34.   okButton = document.documentElement.getButton("accept");
  35.   treeView = Components.classes[nsFileView_CONTRACTID].createInstance(nsIFileView);
  36.  
  37.   if (window.arguments) {
  38.     var o = window.arguments[0];
  39.     retvals = o.retvals; /* set this to a global var so we can set return values */
  40.     const title = o.title;
  41.     filePickerMode = o.mode;
  42.     if (o.displayDirectory) {
  43.       const directory = o.displayDirectory.path;
  44.     }
  45.  
  46.     const initialText = o.defaultString;
  47.     const filterTitles = o.filters.titles;
  48.     const filterTypes = o.filters.types;
  49.     const numFilters = filterTitles.length;
  50.  
  51.     document.title = title;
  52.  
  53.     if (initialText) {
  54.       textInput.value = initialText;
  55.     }
  56.   }
  57.  
  58.   if (filePickerMode != nsIFilePicker.modeOpen && filePickerMode != nsIFilePicker.modeOpenMultiple) {
  59.     var newDirButton = document.getElementById("newDirButton");
  60.     newDirButton.removeAttribute("hidden");
  61.   }
  62.  
  63.   if (filePickerMode == nsIFilePicker.modeGetFolder) {
  64.     var textInputLabel = document.getElementById("textInputLabel");
  65.     textInputLabel.value = gFilePickerBundle.getString("dirTextInputLabel");
  66.   }
  67.   
  68.   if ((filePickerMode == nsIFilePicker.modeOpen) ||
  69.       (filePickerMode == nsIFilePicker.modeOpenMultiple) ||
  70.       (filePickerMode == nsIFilePicker.modeSave)) {
  71.  
  72.     /* build filter popup */
  73.     var filterPopup = document.createElement("menupopup");
  74.  
  75.     for (var i = 0; i < numFilters; i++) {
  76.       var menuItem = document.createElement("menuitem");
  77.       if (filterTypes[i] == "..apps")
  78.         menuItem.setAttribute("label", filterTitles[i]);
  79.       else
  80.         menuItem.setAttribute("label", filterTitles[i] + " (" + filterTypes[i] + ")");
  81.       menuItem.setAttribute("filters", filterTypes[i]);
  82.       filterPopup.appendChild(menuItem);
  83.     }
  84.  
  85.     var filterMenuList = document.getElementById("filterMenuList");
  86.     filterMenuList.appendChild(filterPopup);
  87.     if (numFilters > 0)
  88.       filterMenuList.selectedIndex = 0;
  89.     var filterBox = document.getElementById("filterBox");
  90.     filterBox.removeAttribute("hidden");
  91.  
  92.     filterMenuList.selectedIndex = o.filterIndex;
  93.  
  94.     treeView.setFilter(filterTypes[o.filterIndex]);
  95.  
  96.   } else if (filePickerMode == nsIFilePicker.modeGetFolder) {
  97.     treeView.showOnlyDirectories = true;
  98.   }
  99.  
  100.   // set up the right icon
  101.   if (filePickerMode == nsIFilePicker.modeSave)
  102.     okButton.setAttribute("icon","save");
  103.   else
  104.     okButton.setAttribute("icon","open");
  105.  
  106.   // start out with a filename sort
  107.   handleColumnClick("FilenameColumn");
  108.  
  109.   document.documentElement.setAttribute("ondialogcancel", "return onCancel();");
  110.   try {
  111.     setOKAction();
  112.   } catch (exception) {
  113.     // keep it set to "OK"
  114.   }
  115.  
  116.   // setup the dialogOverlay.xul button handlers
  117.   retvals.buttonStatus = nsIFilePicker.returnCancel;
  118.  
  119.   var tree = document.getElementById("directoryTree");
  120.   if (filePickerMode == nsIFilePicker.modeOpenMultiple)
  121.     tree.removeAttribute("seltype");
  122.  
  123.   tree.treeBoxObject.view = treeView;
  124.  
  125.   // Start out with the ok button disabled since nothing will be
  126.   // selected and nothing will be in the text field.
  127.   okButton.disabled = true;
  128.   textInput.focus();
  129.  
  130.   // This allows the window to show onscreen before we begin
  131.   // loading the file list
  132.  
  133.   setTimeout(setInitialDirectory, 0, directory);
  134. }
  135.  
  136. function setInitialDirectory(directory)
  137. {
  138.   // get the home dir
  139.   var dirServiceProvider = Components.classes[nsIDirectoryServiceProvider_CONTRACTID]
  140.                                      .getService(nsIDirectoryServiceProvider);
  141.   var persistent = new Object();
  142.   homeDir = dirServiceProvider.getFile("Home", persistent);
  143.  
  144.   if (directory) {
  145.     sfile.initWithPath(directory);
  146.   }
  147.   if (!directory || !(sfile.exists() && sfile.isDirectory())) {
  148.     // Start in the user's home directory
  149.     sfile.initWithPath(homeDir.path);
  150.   }
  151.  
  152.   gotoDirectory(sfile);
  153. }
  154.  
  155. function onFilterChanged(target)
  156. {
  157.   // Do this on a timeout callback so the filter list can roll up
  158.   // and we don't keep the mouse grabbed while we are refiltering.
  159.  
  160.   setTimeout(changeFilter, 0, target.getAttribute("filters"));
  161. }
  162.  
  163. function changeFilter(filterTypes)
  164. {
  165.   window.setCursor("wait");
  166.   treeView.setFilter(filterTypes);
  167.   window.setCursor("auto");
  168. }
  169.  
  170. function showErrorDialog(titleStrName, messageStrName, file)
  171. {
  172.   var errorTitle =
  173.     gFilePickerBundle.getFormattedString(titleStrName, [file.path]);
  174.   var errorMessage =
  175.     gFilePickerBundle.getFormattedString(messageStrName, [file.path]);
  176.   var promptService =
  177.     Components.classes[nsIPromptService_CONTRACTID].getService(Components.interfaces.nsIPromptService);
  178.  
  179.   promptService.alert(window, errorTitle, errorMessage);
  180. }
  181.  
  182. function openOnOK()
  183. {
  184.   var dir = treeView.selectedFiles.queryElementAt(0, nsIFile);
  185.   if (!dir.isReadable()) {
  186.     showErrorDialog("errorOpenFileDoesntExistTitle",
  187.                     "errorDirNotReadableMessage",
  188.                     dir);
  189.     return false;
  190.   }
  191.  
  192.   if (dir)
  193.     gotoDirectory(dir);
  194.  
  195.   retvals.fileList = new Array(dir);
  196.  
  197.   retvals.buttonStatus = nsIFilePicker.returnCancel;
  198.   
  199.   var filterMenuList = document.getElementById("filterMenuList");
  200.   retvals.filterIndex = filterMenuList.selectedIndex;
  201.   
  202.   return false;
  203. }
  204.  
  205. function selectOnOK()
  206. {
  207.   var errorTitle, errorMessage, promptService;
  208.   var ret = nsIFilePicker.returnOK;
  209.  
  210.   var isDir = false;
  211.   var isFile = false;
  212.  
  213.   var fileList = processPath(textInput.value);
  214.  
  215.   if (!fileList) { // generic error message, should probably never happen
  216.     showErrorDialog("errorPathProblemTitle",
  217.                     "errorPathProblemMessage",
  218.                     textInput.value);
  219.     return false;
  220.   }
  221.  
  222.   var curFileIndex;
  223.   for (curFileIndex = 0; curFileIndex < fileList.length &&
  224.          ret != nsIFilePicker.returnCancel; ++curFileIndex) {
  225.     var file = fileList[curFileIndex].QueryInterface(nsIFile);
  226.  
  227.     // try to normalize - if this fails we will ignore the error
  228.     // because we will notice the
  229.     // error later and show a fitting error alert.
  230.     try{
  231.       file.normalize();
  232.     } catch(e) {
  233.       //promptService.alert(window, "Problem", "normalize failed, continuing");
  234.     }
  235.  
  236.     var fileExists = file.exists();
  237.  
  238.     if (!fileExists && (filePickerMode == nsIFilePicker.modeOpen ||
  239.                         filePickerMode == nsIFilePicker.modeOpenMultiple)) {
  240.       showErrorDialog("errorOpenFileDoesntExistTitle",
  241.                       "errorOpenFileDoesntExistMessage",
  242.                       file);
  243.       return false;
  244.     }
  245.  
  246.     if (!fileExists && filePickerMode == nsIFilePicker.modeGetFolder) {
  247.       showErrorDialog("errorDirDoesntExistTitle",
  248.                       "errorDirDoesntExistMessage",
  249.                       file);
  250.       return false;
  251.     }
  252.  
  253.     if (fileExists) {
  254.       isDir = file.isDirectory();
  255.       isFile = file.isFile();
  256.     }
  257.  
  258.     switch(filePickerMode) {
  259.     case nsIFilePicker.modeOpen:
  260.     case nsIFilePicker.modeOpenMultiple:
  261.       if (isFile) {
  262.         if (file.isReadable()) {
  263.           retvals.directory = file.parent.path;
  264.         } else {
  265.           showErrorDialog("errorOpeningFileTitle",
  266.                           "openWithoutPermissionMessage_file",
  267.                           file);
  268.           ret = nsIFilePicker.returnCancel;
  269.         }
  270.       } else if (isDir) {
  271.         if (!sfile.equals(file)) {
  272.           gotoDirectory(file);
  273.         }
  274.         textInput.value = "";
  275.         doEnabling();
  276.         ret = nsIFilePicker.returnCancel;
  277.       }
  278.       break;
  279.     case nsIFilePicker.modeSave:
  280.       if (isFile) { // can only be true if file.exists()
  281.         if (!file.isWritable()) {
  282.           showErrorDialog("errorSavingFileTitle",
  283.                           "saveWithoutPermissionMessage_file",
  284.                           file);
  285.           ret = nsIFilePicker.returnCancel;
  286.         } else {
  287.           // we need to pop up a dialog asking if you want to save
  288.           var confirmTitle = gFilePickerBundle.getString("confirmTitle");
  289.           var message =
  290.             gFilePickerBundle.getFormattedString("confirmFileReplacing",
  291.                                                  [file.path]);
  292.           
  293.           promptService = Components.classes[nsIPromptService_CONTRACTID].getService(Components.interfaces.nsIPromptService);
  294.           var rv = promptService.confirm(window, title, message);
  295.           if (rv) {
  296.             ret = nsIFilePicker.returnReplace;
  297.             retvals.directory = file.parent.path;
  298.           } else {
  299.             ret = nsIFilePicker.returnCancel;
  300.           }
  301.         }
  302.       } else if (isDir) {
  303.         if (!sfile.equals(file)) {
  304.           gotoDirectory(file);
  305.         }
  306.         textInput.value = "";
  307.         doEnabling();
  308.         ret = nsIFilePicker.returnCancel;
  309.       } else {
  310.         var parent = file.parent;
  311.         if (parent.exists() && parent.isDirectory() && parent.isWritable()) {
  312.           retvals.directory = parent.path;
  313.         } else {
  314.           var oldParent = parent;
  315.           while (!parent.exists()) {
  316.             oldParent = parent;
  317.             parent = parent.parent;
  318.           }
  319.           errorTitle =
  320.             gFilePickerBundle.getFormattedString("errorSavingFileTitle",
  321.                                                  [file.path]);
  322.           if (parent.isFile()) {
  323.             errorMessage =
  324.               gFilePickerBundle.getFormattedString("saveParentIsFileMessage",
  325.                                                    [parent.path, file.path]);
  326.           } else {
  327.             errorMessage =
  328.               gFilePickerBundle.getFormattedString("saveParentDoesntExistMessage",
  329.                                                    [oldParent.path, file.path]);
  330.           }
  331.           if (!parent.isWritable()) {
  332.             errorMessage =
  333.               gFilePickerBundle.getFormattedString("saveWithoutPermissionMessage_dir", [parent.path]);
  334.           }
  335.           promptService = Components.classes[nsIPromptService_CONTRACTID].getService(Components.interfaces.nsIPromptService);
  336.           promptService.alert(window, errorTitle, errorMessage);
  337.           ret = nsIFilePicker.returnCancel;
  338.         }
  339.       }
  340.       break;
  341.     case nsIFilePicker.modeGetFolder:
  342.       if (isDir) {
  343.         retvals.directory = file.parent.path;
  344.       } else { // if nothing selected, the current directory will be fine
  345.         retvals.directory = sfile.path;
  346.       }
  347.       break;
  348.     }
  349.   }
  350.  
  351.   gFilesEnumerator.mFiles = fileList;
  352.  
  353.   retvals.files = gFilesEnumerator;
  354.   retvals.buttonStatus = ret;
  355.  
  356.   var filterMenuList = document.getElementById("filterMenuList");
  357.   retvals.filterIndex = filterMenuList.selectedIndex;
  358.   
  359.   return (ret != nsIFilePicker.returnCancel);
  360. }
  361.  
  362. var gFilesEnumerator = {
  363.   mFiles: null,
  364.   mIndex: 0,
  365.  
  366.   hasMoreElements: function()
  367.   {
  368.     return (this.mIndex < this.mFiles.length);
  369.   },
  370.   getNext: function()
  371.   {
  372.     if (this.mIndex >= this.mFiles.length)
  373.       throw Components.results.NS_ERROR_FAILURE;
  374.     return this.mFiles[this.mIndex++];
  375.   }
  376. };
  377.  
  378. function onCancel()
  379. {
  380.   // Close the window.
  381.   retvals.buttonStatus = nsIFilePicker.returnCancel;
  382.   retvals.file = null;
  383.   retvals.files = null;
  384.   return true;
  385. }
  386.  
  387. function onDblClick(e) {
  388.   // we only care about button 0 (left click) events
  389.   if (e.button != 0) return;
  390.  
  391.   var t = e.originalTarget;
  392.   if (t.localName != "treechildren")
  393.     return;
  394.  
  395.   openSelectedFile();
  396. }
  397.  
  398. function openSelectedFile() {
  399.   var fileList = treeView.selectedFiles;
  400.   if (fileList.length == 0)
  401.     return;
  402.  
  403.   var file = fileList.queryElementAt(0, nsIFile);
  404.   if (file.isDirectory())
  405.     gotoDirectory(file);
  406.   else if (file.isFile())
  407.     document.documentElement.acceptDialog();
  408. }
  409.  
  410. function onClick(e) {
  411.   var t = e.originalTarget;
  412.   if (t.localName == "treecol")
  413.     handleColumnClick(t.id);
  414. }
  415.  
  416. function convertColumnIDtoSortType(columnID) {
  417.   var sortKey;
  418.   
  419.   switch (columnID) {
  420.   case "FilenameColumn":
  421.     sortKey = nsIFileView.sortName;
  422.     break;
  423.   case "FileSizeColumn":
  424.     sortKey = nsIFileView.sortSize;
  425.     break;
  426.   case "LastModifiedColumn":
  427.     sortKey = nsIFileView.sortDate;
  428.     break;
  429.   default:
  430.     dump("unsupported sort column: " + columnID + "\n");
  431.     sortKey = 0;
  432.     break;
  433.   }
  434.   
  435.   return sortKey;
  436. }
  437.  
  438. function handleColumnClick(columnID) {
  439.   var sortType = convertColumnIDtoSortType(columnID);
  440.   var sortOrder = (treeView.sortType == sortType) ? !treeView.reverseSort : false;
  441.   treeView.sort(sortType, sortOrder);
  442.   
  443.   // set the sort indicator on the column we are sorted by
  444.   var sortedColumn = document.getElementById(columnID);
  445.   if (treeView.reverseSort) {
  446.     sortedColumn.setAttribute("sortDirection", "descending");
  447.   } else {
  448.     sortedColumn.setAttribute("sortDirection", "ascending");
  449.   }
  450.   
  451.   // remove the sort indicator from the rest of the columns
  452.   var currCol = sortedColumn.parentNode.firstChild;
  453.   while (currCol) {
  454.     if (currCol != sortedColumn && currCol.localName == "treecol")
  455.       currCol.removeAttribute("sortDirection");
  456.     currCol = currCol.nextSibling;
  457.   }
  458. }
  459.  
  460. function onKeypress(e) {
  461.   if (e.keyCode == 8) /* backspace */
  462.     goUp();
  463.  
  464.   /* enter is handled by the ondialogaccept handler */
  465. }
  466.  
  467. function doEnabling() {
  468.   // Maybe add check if textInput.value would resolve to an existing
  469.   // file or directory in .modeOpen. Too costly I think.
  470.   var enable = (textInput.value != "");
  471.  
  472.   okButton.disabled = !enable;
  473. }
  474.  
  475. function onTreeFocus(event) {
  476.   // Reset the button label and enabled/disabled state.
  477.   onFileSelected(treeView.selectedFiles);
  478. }
  479.  
  480. function setOKAction(file) {
  481.   var buttonLabel;
  482.   var buttonIcon = "open"; // used in all but one case
  483.  
  484.   if (file && file.isDirectory() && filePickerMode != nsIFilePicker.modeGetFolder) {
  485.     document.documentElement.setAttribute("ondialogaccept", "return openOnOK();");
  486.     buttonLabel = gFilePickerBundle.getString("openButtonLabel");
  487.   }
  488.   else {
  489.     document.documentElement.setAttribute("ondialogaccept", "return selectOnOK();");
  490.     switch(filePickerMode) {
  491.     case nsIFilePicker.modeGetFolder:
  492.       buttonLabel = gFilePickerBundle.getString("selectFolderButtonLabel");
  493.       break;
  494.     case nsIFilePicker.modeOpen:
  495.     case nsIFilePicker.modeOpenMultiple:
  496.       buttonLabel = gFilePickerBundle.getString("openButtonLabel");
  497.       break;
  498.     case nsIFilePicker.modeSave:
  499.       buttonLabel = gFilePickerBundle.getString("saveButtonLabel");
  500.       buttonIcon = "save";
  501.       break;
  502.     }
  503.   }
  504.   okButton.setAttribute("label", buttonLabel);
  505.   okButton.setAttribute("icon", buttonIcon);
  506. }
  507.  
  508. function onSelect(event) {
  509.   onFileSelected(treeView.selectedFiles);
  510. }
  511.  
  512. function onFileSelected(/* nsIArray */ selectedFileList) {
  513.   var validFileSelected = false;
  514.   var invalidSelection = false;
  515.   var file;
  516.   var fileCount = selectedFileList.length;
  517.  
  518.   for (var index = 0; index < fileCount; ++index) {
  519.     file = selectedFileList.queryElementAt(index, nsIFile);
  520.     if (file) {
  521.       var path = file.leafName;
  522.  
  523.       if (path) {
  524.         var isDir = file.isDirectory();
  525.         if ((filePickerMode == nsIFilePicker.modeGetFolder) || !isDir) {
  526.           if (!validFileSelected)
  527.             textInput.value = "";
  528.           addToTextFieldValue(path);
  529.         }
  530.  
  531.         if (isDir && fileCount > 1) {
  532.           // The user has selected multiple items, and one of them is
  533.           // a directory.  This is not a valid state, so we'll disable
  534.           // the ok button.
  535.           invalidSelection = true;
  536.         }
  537.  
  538.         validFileSelected = true;
  539.       }
  540.     }
  541.   }
  542.  
  543.   if (validFileSelected) {
  544.     setOKAction(file);
  545.     okButton.disabled = invalidSelection;
  546.   } else
  547.     okButton.disabled = (textInput.value == "");
  548. }
  549.  
  550. function addToTextFieldValue(path)
  551. {
  552.   var newValue = "";
  553.  
  554.   if (textInput.value == "")
  555.     newValue = path.replace(/\"/g, "\\\"");
  556.   else {
  557.     // Quote the existing text if needed,
  558.     // then append the new filename (quoted and escaped)
  559.     if (textInput.value[0] != '"')
  560.       newValue = '"' + textInput.value.replace(/\"/g, "\\\"") + '"';
  561.     else
  562.       newValue = textInput.value;
  563.  
  564.     newValue = newValue + ' "' + path.replace(/\"/g, "\\\"") + '"';
  565.   }
  566.  
  567.   textInput.value = newValue;
  568. }
  569.  
  570. function onTextFieldFocus() {
  571.   setOKAction(null);
  572.   doEnabling();
  573. }
  574.  
  575. function onDirectoryChanged(target)
  576. {
  577.   var path = target.getAttribute("label");
  578.  
  579.   var file = Components.classes[nsLocalFile_CONTRACTID].createInstance(nsILocalFile);
  580.   file.initWithPath(path);
  581.  
  582.   if (!sfile.equals(file)) {
  583.     // Do this on a timeout callback so the directory list can roll up
  584.     // and we don't keep the mouse grabbed while we are loading.
  585.  
  586.     setTimeout(gotoDirectory, 0, file);
  587.   }
  588. }
  589.  
  590. function populateAncestorList(directory) {
  591.   var menu = document.getElementById("lookInMenu");
  592.  
  593.   while (menu.hasChildNodes()) {
  594.     menu.removeChild(menu.firstChild);
  595.   }
  596.   
  597.   var menuItem = document.createElement("menuitem");
  598.   menuItem.setAttribute("label", directory.path);
  599.   menuItem.setAttribute("crop", "start");
  600.   menu.appendChild(menuItem);
  601.  
  602.   // .parent is _sometimes_ null, see bug 121489.  Do a dance around that.
  603.   var parent = directory.parent;
  604.   while (parent && !parent.equals(directory)) {
  605.     menuItem = document.createElement("menuitem");
  606.     menuItem.setAttribute("label", parent.path);
  607.     menuItem.setAttribute("crop", "start");
  608.     menu.appendChild(menuItem);
  609.     directory = parent;
  610.     parent = directory.parent;
  611.   }
  612.   
  613.   var menuList = document.getElementById("lookInMenuList");
  614.   menuList.selectedIndex = 0;
  615. }
  616.  
  617. function goUp() {
  618.   try {
  619.     var parent = sfile.parent;
  620.   } catch(ex) { dump("can't get parent directory\n"); }
  621.  
  622.   if (parent) {
  623.     gotoDirectory(parent);
  624.   }
  625. }
  626.  
  627. function goHome() {
  628.   gotoDirectory(homeDir);
  629. }
  630.  
  631. function newDir() {
  632.   var file;
  633.   var promptService =
  634.     Components.classes[nsIPromptService_CONTRACTID].getService(Components.interfaces.nsIPromptService);
  635.   var dialogTitle =
  636.     gFilePickerBundle.getString("promptNewDirTitle");
  637.   var dialogMsg =
  638.     gFilePickerBundle.getString("promptNewDirMessage");
  639.   var ret = promptService.prompt(window, dialogTitle, dialogMsg, gNewDirName, null, {value:0});
  640.  
  641.   if (ret) {
  642.     file = processPath(gNewDirName.value);
  643.     if (!file) {
  644.       showErrorDialog("errorCreateNewDirTitle",
  645.                       "errorCreateNewDirMessage",
  646.                       file);
  647.       return false;
  648.     }
  649.     
  650.     file = file[0].QueryInterface(nsIFile);
  651.     if (file.exists()) {
  652.       showErrorDialog("errorNewDirDoesExistTitle",
  653.                       "errorNewDirDoesExistMessage",
  654.                       file);
  655.       return false;
  656.     }
  657.  
  658.     var parent = file.parent;
  659.     if (!(parent.exists() && parent.isDirectory() && parent.isWritable())) {
  660.       var oldParent = parent;
  661.       while (!parent.exists()) {
  662.         oldParent = parent;
  663.         parent = parent.parent;
  664.       }
  665.       if (parent.isFile()) {
  666.         showErrorDialog("errorCreateNewDirTitle",
  667.                         "errorCreateNewDirIsFileMessage",
  668.                         parent);
  669.         return false;
  670.       }
  671.       if (!parent.isWritable()) {
  672.         showErrorDialog("errorCreateNewDirTitle",
  673.                         "errorCreateNewDirPermissionMessage",
  674.                         parent);
  675.         return false;
  676.       }
  677.     }
  678.  
  679.     try {
  680.       file.create(nsIFile.DIRECTORY_TYPE, 0755); 
  681.     } catch (e) {
  682.       showErrorDialog("errorCreateNewDirTitle",
  683.                       "errorCreateNewDirMessage",
  684.                       file);
  685.       return false;
  686.     }
  687.     file.normalize(); // ... in case ".." was used in the path
  688.     gotoDirectory(file);
  689.     // we remember and reshow a dirname if something goes wrong
  690.     // so that errors can be corrected more easily. If all went well,
  691.     // reset the default value to blank
  692.     gNewDirName = { value: "" }; 
  693.   }
  694.   return true;
  695. }
  696.  
  697. function gotoDirectory(directory) {
  698.   window.setCursor("wait");
  699.   try {
  700.     populateAncestorList(directory);
  701.     treeView.setDirectory(directory);
  702.     document.getElementById("errorShower").selectedIndex = 0;
  703.   } catch(ex) {
  704.     document.getElementById("errorShower").selectedIndex = 1;
  705.   }
  706.  
  707.   window.setCursor("auto");
  708.  
  709.   treeView.QueryInterface(nsITreeView).selection.clearSelection();
  710.   if (filePickerMode == nsIFilePicker.modeGetFolder) {
  711.     textInput.value = "";
  712.   }
  713.   textInput.focus();
  714.   sfile = directory;
  715. }
  716.  
  717. function toggleShowHidden(event) {
  718.   treeView.showHiddenFiles = !treeView.showHiddenFiles;
  719. }
  720.  
  721. // from the current directory and whatever was entered
  722. // in the entry field, try to make a new path. This
  723. // uses "/" as the directory seperator, "~" as a shortcut
  724. // for the home directory (but only when seen at the start
  725. // of a path), and ".." to denote the parent directory.
  726. // returns an array of the files listed,
  727. // or false if an error occurred.
  728. function processPath(path)
  729. {
  730.   var fileArray = new Array();
  731.   var strLength = path.length;
  732.  
  733.   if (path[0] == '"' && filePickerMode == nsIFilePicker.modeOpenMultiple &&
  734.       strLength > 1) {
  735.     // we have a quoted list of filenames, separated by spaces.
  736.     // iterate the list and process each file.
  737.  
  738.     var curFileStart = 1;
  739.  
  740.     while (1) {
  741.       var nextQuote;
  742.  
  743.       // Look for an unescaped quote
  744.       var quoteSearchStart = curFileStart + 1;
  745.       do {
  746.         nextQuote = path.indexOf('"', quoteSearchStart);
  747.         quoteSearchStart = nextQuote + 1;
  748.       } while (nextQuote != -1 && path[nextQuote - 1] == '\\');
  749.       
  750.       if (nextQuote == -1) {
  751.         // we have a filename with no trailing quote.
  752.         // just assume that the filename ends at the end of the string.
  753.  
  754.         if (!processPathEntry(path.substring(curFileStart), fileArray))
  755.           return false;
  756.         break;
  757.       }
  758.  
  759.       if (!processPathEntry(path.substring(curFileStart, nextQuote), fileArray))
  760.         return false;
  761.  
  762.       curFileStart = path.indexOf('"', nextQuote + 1);
  763.       if (curFileStart == -1) {
  764.         // no more quotes, but if we're not at the end of the string,
  765.         // go ahead and process the remaining text.
  766.  
  767.         if (nextQuote < strLength - 1)
  768.           if (!processPathEntry(path.substring(nextQuote + 1), fileArray))
  769.             return false;
  770.         break;
  771.       }
  772.       ++curFileStart;
  773.     }
  774.   } else {
  775.     // If we didn't start with a quote, assume we just have a single file.
  776.     if (!processPathEntry(path, fileArray))
  777.       return false;
  778.   }
  779.  
  780.   return fileArray;
  781. }
  782.  
  783. function processPathEntry(path, fileArray)
  784. {
  785.   var filePath;
  786.   var file;
  787.  
  788.   if (path[0] == '~') 
  789.     filePath = homeDir.path + path.substring(1);
  790.   else
  791.     filePath = path;
  792.  
  793.   // Unescape quotes
  794.   filePath = filePath.replace(/\\\"/g, "\"");
  795.   
  796.   try{
  797.     file = sfile.clone().QueryInterface(nsILocalFile);
  798.   } catch(e) {
  799.     dump("Couldn't clone\n"+e);
  800.     return false;
  801.   }
  802.  
  803.   if (filePath[0] == '/')   /* an absolute path was entered */
  804.     file.initWithPath(filePath);
  805.   else if ((filePath.indexOf("/../") > 0) ||
  806.            (filePath.substr(-3) == "/..") ||
  807.            (filePath.substr(0,3) == "../") ||
  808.            (filePath == "..")) {
  809.     /* appendRelativePath doesn't allow .. */
  810.     try{
  811.       file.initWithPath(file.path + "/" + filePath);
  812.     } catch (e) {
  813.       dump("Couldn't init path\n"+e);
  814.       return false;
  815.     }
  816.   }
  817.   else {
  818.     try {
  819.       file.appendRelativePath(filePath);
  820.     } catch (e) {
  821.       dump("Couldn't append path\n"+e);
  822.       return false;
  823.     }
  824.   }
  825.  
  826.   fileArray[fileArray.length] = file;
  827.   return true;
  828. }
  829.